#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>


typedef struct{
    int num_piece;
    int ligne;
    int colonne;
    int rotation;
    int nord;
    int sud;
    int est;
    int ouest;

}Piece;


typedef struct{
    int taille;
    int nbCouleur;
    Piece Pieces[100];
}Puzzle;

typedef struct{
	int lig;
	int col;
}Position;

Puzzle Eternity;
int tab_piece_rest [100]; //numero des pieces non placées
Position ordre[100];

int trouve_piece(Puzzle puzz, int lig, int col){
	int i=0;
	int trouve=0;

	while(i<puzz.taille || trouve==1)
	{

		if(puzz.Pieces[i].colonne==col && puzz.Pieces[i].ligne==lig)
		{
			trouve=1;
		}
		else
		{
			i++;
		}
	}

	if(trouve == 1)
	{
		return puzz.Pieces[i].num_piece;
		printf("piece trouvee n°: %i", puzz.Pieces[i].num_piece);
	}
	else
		return -1;
}

int voisinage(Puzzle puzz,int num_p,Position pos,int orientation){
	int swap, swap1, swap2;
	switch (orientation)
	{
		case 1:
			swap = puzz.Pieces[num_p].nord;
			puzz.Pieces[num_p].nord = puzz.Pieces[num_p].est;
			puzz.Pieces[num_p].est = puzz.Pieces[num_p].sud;
			puzz.Pieces[num_p].sud = puzz.Pieces[num_p].ouest;
			puzz.Pieces[num_p].ouest = swap;
			break;
		case 2 :
			swap1 = puzz.Pieces[num_p].nord;
			swap2 = puzz.Pieces[num_p].ouest;
			puzz.Pieces[num_p].nord = puzz.Pieces[num_p].sud;
			puzz.Pieces[num_p].ouest = puzz.Pieces[num_p].est;
			puzz.Pieces[num_p].est = swap2;
			puzz.Pieces[num_p].sud = swap1;
			break;
		case 3 :
			swap1 = puzz.Pieces[num_p].nord;
			puzz.Pieces[num_p].nord = puzz.Pieces[num_p].ouest;
			puzz.Pieces[num_p].ouest = puzz.Pieces[num_p].sud;
			puzz.Pieces[num_p].sud = puzz.Pieces[num_p].est;
			puzz.Pieces[num_p].est = swap1;
			break;
		default :
		break;
	}



	int max = sqrt(puzz.taille);
	if(pos.lig==1 && pos.col==1) //pièce coin haut gauche
	{
printf("TEST coin haut gauche\n");
		if(trouve_piece(puzz,pos.lig,pos.col+1)==-1 && trouve_piece(puzz,pos.lig+1,pos.col)==-1) //pas de pièce placée à droite ni en bas
		{
printf("****coin haut gauche place\n");
			return 1; //voisinage ok !
		}
		else if(trouve_piece(puzz,pos.lig,pos.col+1)==-1 || puzz.Pieces[num_p].est == puzz.Pieces[trouve_piece(puzz,pos.lig,pos.col+1)].ouest) //on teste à droite
		{
			if(trouve_piece(puzz,pos.lig+1,pos.col)==-1 || puzz.Pieces[num_p].sud == puzz.Pieces[trouve_piece(puzz,pos.lig+1,pos.col)].nord) //on teste en bas
				{
					return 1;  //voisinage ok !
				}
				else
				{
					return 0; // pas bon en bas !
				}
		}
		else
		{
			return 0; //pas bon à droite !
		}
	}
	else if(pos.lig==1 && pos.col==max) //pièce coin haut droite
	{
		if(trouve_piece(puzz,pos.lig,pos.col-1)==-1 && trouve_piece(puzz,pos.lig+1,pos.col)==-1) //pas de pièce placée à gauche ni en bas
		{
			return 1; //voisinage ok !
		}
		else if(trouve_piece(puzz,pos.lig,pos.col-1)==-1 || puzz.Pieces[num_p].ouest == puzz.Pieces[trouve_piece(puzz,pos.lig,pos.col-1)].est) //on teste à gauche
		{
			if(trouve_piece(puzz,pos.lig+1,pos.col)==-1 || puzz.Pieces[num_p].sud == puzz.Pieces[trouve_piece(puzz,pos.lig+1,pos.col)].nord) //on teste en bas
				{
					return 1;  //voisinage ok !
				}
				else
				{
					return 0; // pas bon en bas !
				}
		}
		else
		{
			return 0; //pas bon à gauche !
		}
	}
	else if(pos.lig==max && pos.col==max) //pièce coin bas droite
	{
		if(trouve_piece(puzz,pos.lig,pos.col-1)==-1 && trouve_piece(puzz,pos.lig-1,pos.col)==-1) //pas de pièce placée à gauche ni en haut
		{
			return 1; //voisinage ok !
		}
		else if(trouve_piece(puzz,pos.lig,pos.col-1)==-1 || puzz.Pieces[num_p].ouest == puzz.Pieces[trouve_piece(puzz,pos.lig,pos.col-1)].est) //on teste à gauche
		{
			if(trouve_piece(puzz,pos.lig-1,pos.col)==-1 || puzz.Pieces[num_p].nord == puzz.Pieces[trouve_piece(puzz,pos.lig-1,pos.col)].sud) //on teste en haut
				{
					return 1;  //voisinage ok !
				}
				else
				{
					return 0; // pas bon en bas !
				}
		}
		else
		{
			return 0; //pas bon à gauche !
		}
	}
	else if(pos.lig==max && pos.col==1) //pièce coin bas gauche
	{
		if(trouve_piece(puzz,pos.lig-1,pos.col)==-1 && trouve_piece(puzz,pos.lig,pos.col+1)==-1) //pas de pièce placée à droite ni en haut
		{
			return 1; //voisinage ok !
		}
		else if(trouve_piece(puzz,pos.lig,pos.col+1)==-1 || puzz.Pieces[num_p].est == puzz.Pieces[trouve_piece(puzz,pos.lig,pos.col+1)].ouest) //on teste à droite
		{
			if(trouve_piece(puzz,pos.lig-1,pos.col)==-1 || puzz.Pieces[num_p].nord == puzz.Pieces[trouve_piece(puzz,pos.lig-1,pos.col)].sud) //on teste en haut
				{
					return 1;  //voisinage ok !
				}
				else
				{
					return 0; // pas bon en bas !
				}
		}
		else
		{
			return 0; //pas bon à gauche !
		}
	}
	else if(pos.lig==1) //pièce ligne haut
	{
		if(trouve_piece(puzz,pos.lig,pos.col-1)==-1 && trouve_piece(puzz,pos.lig+1,pos.col)==-1 && trouve_piece(puzz,pos.lig,pos.col+1)==-1)
		//pas de pièce placée à gauche ni en bas ni à droite
		{
			return 1; //voisinage ok !
		}
		else if(trouve_piece(puzz,pos.lig,pos.col-1)==-1 || puzz.Pieces[num_p].ouest == puzz.Pieces[trouve_piece(puzz,pos.lig,pos.col-1)].est) //on teste à gauche
		{
printf("Piece 1ere ligne peut aller a gauche\n");
			if(trouve_piece(puzz,pos.lig+1,pos.col)==-1 || puzz.Pieces[num_p].sud == puzz.Pieces[trouve_piece(puzz,pos.lig+1,pos.col)].nord){ //on teste en bas

					if(trouve_piece(puzz,pos.lig,pos.col+1)==-1 || puzz.Pieces[num_p].est == puzz.Pieces[trouve_piece(puzz,pos.lig,pos.col+1)].ouest) //on teste à droite
					{
						return 1;  //voisinage ok !
					}
					else
					{
						return 0; // pas bon à droite
					}
			}
			else
			{
				return 0; // pas bon en bas !
			}
		}
		else
		{
			return 0; //pas bon à gauche !
		}
	}
		else if(pos.lig==max) //pièce ligne bas
	{
		if(trouve_piece(puzz,pos.lig,pos.col-1)==-1 && trouve_piece(puzz,pos.lig-1,pos.col)==-1 && trouve_piece(puzz,pos.lig,pos.col+1)==-1)
		//pas de pièce placée à gauche ni en haut ni à droite
		{
			return 1; //voisinage ok !
		}
		else if(trouve_piece(puzz,pos.lig,pos.col-1)==-1 || puzz.Pieces[num_p].ouest == puzz.Pieces[trouve_piece(puzz,pos.lig,pos.col-1)].est) //on teste à gauche
		{
			if(trouve_piece(puzz,pos.lig-1,pos.col)==-1 || puzz.Pieces[num_p].nord == puzz.Pieces[trouve_piece(puzz,pos.lig-1,pos.col)].sud){ //on teste en haut

					if(trouve_piece(puzz,pos.lig,pos.col+1)==-1 || puzz.Pieces[num_p].est == puzz.Pieces[trouve_piece(puzz,pos.lig,pos.col+1)].ouest) //on teste à droite
					{
						return 1;  //voisinage ok !
					}
					else
					{
						return 0; // pas bon à droite
					}
			}
			else
			{
				return 0; // pas bon en haut !
			}
		}
		else
		{
			return 0; //pas bon à gauche !
		}
	}
		else if(pos.col==max) //pièce colonne droite
	{
		if(trouve_piece(puzz,pos.lig,pos.col-1)==-1 && trouve_piece(puzz,pos.lig+1,pos.col)==-1 && trouve_piece(puzz,pos.lig-1,pos.col)==-1)
		//pas de pièce placée à gauche ni en bas ni à haut
		{
			return 1; //voisinage ok !
		}
		else if(trouve_piece(puzz,pos.lig,pos.col-1)==-1 || puzz.Pieces[num_p].ouest == puzz.Pieces[trouve_piece(puzz,pos.lig,pos.col-1)].est) //on teste à gauche
		{
			if(trouve_piece(puzz,pos.lig+1,pos.col)==-1 || puzz.Pieces[num_p].nord == puzz.Pieces[trouve_piece(puzz,pos.lig+1,pos.col)].sud){ //on teste en bas

					if(trouve_piece(puzz,pos.lig-1,pos.col)==-1 || puzz.Pieces[num_p].nord == puzz.Pieces[trouve_piece(puzz,pos.lig-1,pos.col)].sud) //on teste en haut
					{
						return 1;  //voisinage ok !
					}
					else
					{
						return 0; //pas bon en haut
					}
			}
			else
			{
				return 0; // pas bon en bas !
			}
		}
		else
		{
			return 0; //pas bon à gauche !
		}
	}
			else if(pos.col==max) //pièce colonne gauche
	{
		if(trouve_piece(puzz,pos.lig,pos.col+1)==-1 && trouve_piece(puzz,pos.lig+1,pos.col)==-1 && trouve_piece(puzz,pos.lig-1,pos.col)==-1)
		//pas de pièce placée à droite ni en bas ni à haut
		{
			return 1; //voisinage ok !
		}
		else if(trouve_piece(puzz,pos.lig,pos.col+1)==-1 || puzz.Pieces[num_p].est == puzz.Pieces[trouve_piece(puzz,pos.lig,pos.col+1)].ouest) //on teste à droite
		{
			if(trouve_piece(puzz,pos.lig+1,pos.col)==-1 || puzz.Pieces[num_p].nord == puzz.Pieces[trouve_piece(puzz,pos.lig+1,pos.col)].sud){ //on teste en bas

					if(trouve_piece(puzz,pos.lig-1,pos.col)==-1 || puzz.Pieces[num_p].nord == puzz.Pieces[trouve_piece(puzz,pos.lig-1,pos.col)].sud) //on teste en haut
					{
						return 1;  //voisinage ok !
					}
					else
					{
						return 0; // pas bon en haut
					}
			}
			else
			{
				return 0; // pas bon en bas !
			}
		}
		else
		{
			return 0; //pas bon à droite !
		}
	}
	else
	{
		if(trouve_piece(puzz,pos.lig,pos.col-1)==-1 && trouve_piece(puzz,pos.lig,pos.col+1)==-1 && trouve_piece(puzz,pos.lig+1,pos.col)==-1 && trouve_piece(puzz,pos.lig-1,pos.col)==-1)
		//pas de pièce placée à droite, ni à gauche ni en bas ni à haut
		{
			return 1; //voisinage ok !
		}
			else if(trouve_piece(puzz,pos.lig,pos.col+1)==-1 || puzz.Pieces[num_p].est == puzz.Pieces[trouve_piece(puzz,pos.lig,pos.col+1)].ouest) //on teste à droite
		{
			if(trouve_piece(puzz,pos.lig+1,pos.col)==-1 || puzz.Pieces[num_p].sud == puzz.Pieces[trouve_piece(puzz,pos.lig+1,pos.col)].nord){ //on teste en bas

					if(trouve_piece(puzz,pos.lig-1,pos.col)==-1 || puzz.Pieces[num_p].nord == puzz.Pieces[trouve_piece(puzz,pos.lig-1,pos.col)].sud) {//on teste en haut
						 if(trouve_piece(puzz,pos.lig,pos.col-1)==-1 || puzz.Pieces[num_p].ouest == puzz.Pieces[trouve_piece(puzz,pos.lig,pos.col-1)].est) //on teste à gauche
							{
								return 1;  //voisinage ok !
							}
							else
							{
								return 0; // pas bon a gauche
							}
					}
					else
					{
						return 0; //pas bon en haut
					}
			}
			else
			{
				return 0; // pas bon en bas !
			}
		}
		else
		{
			return 0; //pas bon à droite !
		}
	}

}

//pas bon puzzle, mieux vaut faire passer une liste des pieces a placer pour pouvoir l'enlever
//pas bon position, envoyer juste un num de position et l'incrementer a chaque passage dans solver
int solver(Puzzle puzzle, Position* pos, int ind_pos, int* tab_piece_rest){
	int i=0;
	int j=0;


	for(i=0; i<puzzle.taille; i++)
	{
printf("on regarde pour i vaut %i\n", i);
		for(j=0; j<4; j++)
		{
printf("on regarde pour j vaut %i\n", j);
			if(tab_piece_rest[puzzle.Pieces[i].num_piece] != 0)
			{


				//si la piece peut etre placée
				if (voisinage(puzzle, puzzle.Pieces[i].num_piece, pos[ind_pos], j)==1)
				{
printf("On place la piece: %i et à lig= %i et col= %i\n", tab_piece_rest[puzzle.Pieces[i].num_piece], pos[ind_pos].lig, pos[ind_pos].col);
					puzzle.Pieces[i].ligne = pos[i].lig;
					puzzle.Pieces[i].colonne = pos[i].col;
					tab_piece_rest[puzzle.Pieces[i].num_piece] = 0;
					//ecrire dans le fichier texte pour avoir toutes les pieces bien placées dedans et pouvoir lire directement avec la visionneuse
					solver(puzzle, pos, ind_pos+1, tab_piece_rest);//(liste moins la piece placee, position + 1)
					//enlever la piece du puzzle, si on est bloqué à un moment, il faut enlever la piece du puzzle sinon ca nous bloquera
					tab_piece_rest[puzzle.Pieces[i].num_piece] = puzzle.Pieces[i].num_piece;
					puzzle.Pieces[i].ligne = -1;
					puzzle.Pieces[i].colonne = -1;

				}
				//si voisinage pas bon alors on remet la piece dans sa position initiale
				else
				{
					int swap, swap1, swap2, swap3;
					switch (j)
					{
					case 1 :
						swap = puzzle.Pieces[i].nord;
						puzzle.Pieces[i].nord = puzzle.Pieces[i].ouest;
						puzzle.Pieces[i].ouest = puzzle.Pieces[i].sud;
						puzzle.Pieces[i].sud = puzzle.Pieces[i].est;
						puzzle.Pieces[i].est = swap;
						break;
					case 2 :
						swap1 = puzzle.Pieces[i].est;
						swap2 = puzzle.Pieces[i].nord;
						puzzle.Pieces[i].est = puzzle.Pieces[i].ouest;
						puzzle.Pieces[i].nord = puzzle.Pieces[i].sud;
						puzzle.Pieces[i].ouest = swap1;
						puzzle.Pieces[i].sud = swap2;
						break;
					case 3 :
						swap3 = puzzle.Pieces[i].est;

						puzzle.Pieces[i].est = puzzle.Pieces[i].sud;//sud
						puzzle.Pieces[i].sud = puzzle.Pieces[i].ouest;
						puzzle.Pieces[i].ouest = puzzle.Pieces[i].nord;//nord
						puzzle.Pieces[i].nord = swap3;
						break;
					default :
					break;
					}
				}
			}

		}
	}
}

//rempli un tableau d'ordre contenant les positions des pieces à placer en premier
void rempli_ordre()
{
	int nb_planif = 0;
	FILE* fd;

	if (fd = fopen("ordre.txt", "r") != 0)
	{
		fd = fopen("ordre.txt", "r");

		int nombrelu= 0;
		int dejalu = 0;

		while(fscanf(fd, "%i", &nombrelu)==1)
		//while(fscanf(fd, "%i%i", &ordre[nb_planif].lig, &ordre[nb_planif].col))
		{
			if(dejalu == 0 && nombrelu == 0)
			{
				dejalu = 1;
				ordre[nb_planif].lig = (nombrelu/10)+1;
				ordre[nb_planif].col = (nombrelu%10)+1;
				printf("%i, %i \n", ordre[nb_planif].lig, ordre[nb_planif].col);
				
				nb_planif++;
			}
			else if(nombrelu != 00 && dejalu == 1)
			{
				ordre[nb_planif].lig = (nombrelu/10)+1;
				ordre[nb_planif].col = (nombrelu%10)+1;
				printf("%i, %i \n", ordre[nb_planif].lig, ordre[nb_planif].col);
				
				nb_planif++;
			}
		}

	}

	fclose(fd);
}

int main(int argc, char** argv){
//initialisation des variables
	FILE* fd;
	int N, E, S, O;
	int row, col, p_num, rot;
	int taille, nb_coul;
	int nb = 0;
	int nb_hint=0;
	int ind = 0;
	int carac_lus = 0;

for(int i=0; i<100;i++)
{
	tab_piece_rest[i] = -1;
}
	//remplissage du tableau ordre en fonction planificateur

	rempli_ordre();

	//if (fd = fopen(argv[1], "r") != 0){
	  if (fd = fopen("pieces.txt", "r") != 0){

		fd = fopen("pieces.txt", "r");
		printf("fichier ouvert\n");

		fscanf(fd, "%i%i%i", &taille, &nb_coul, &nb_hint); //on lit les en-tetes
		Eternity.taille = taille*taille;
		printf("taille du puzzle : %i\n", Eternity.taille);
		Eternity.nbCouleur = nb_coul;
		printf("nombre de couleurs du puzzle: %i\n", Eternity.nbCouleur);

		//allocation du tableau de hints
		if(nb_hint < 100 && nb_hint > 0)
		{
			printf("nombre de hints : %i\n", nb_hint);
	//		Puzzle.hints = malloc(nb_hint*sizeof(struct Piece)); 		//allocation du tableau de hints
//			int *tab_hint[nb_hint];
		}
		else{
			printf("pas cool... \n");
		}


		while(fscanf(fd, "%i%i%i%i", &row, &col, &p_num, &rot)==4 && ind < nb_hint){ //tant que j'arrive à lire 4 variables et qu'il reste des hints, on lit les hints

			Eternity.Pieces[p_num].num_piece=p_num;
			Eternity.Pieces[p_num].ligne=row;
			Eternity.Pieces[p_num].colonne=col;
			Eternity.Pieces[p_num].rotation=rot;
			
			printf("lecture du hint n°%i : %i%i%i%i\n",ind, Eternity.Pieces[p_num].ligne, Eternity.Pieces[p_num].colonne, Eternity.Pieces[p_num].num_piece, Eternity.Pieces[p_num].rotation);
			ind++;

			tab_piece_rest[p_num] = 0; //on met à 0 pour dire au solver qu'il n'a pas a toucher à ces pièces, elles sont déjà bien placées
		}

		while(fscanf(fd, "%i%i%i%i", &N, &E, &S, &O)==4){			//tant que j'arrive à lire 4 variables, on lit les pieces
			Eternity.Pieces[nb].num_piece = nb;
			Eternity.Pieces[nb].nord=N;
			Eternity.Pieces[nb].est=E;
			Eternity.Pieces[nb].sud=S;
			Eternity.Pieces[nb].ouest=O;
			//si la piece courante est un hint, on laisse ses valeurs
			if(tab_piece_rest[nb] != 0)
			{
				Eternity.Pieces[nb].colonne = -1;
				Eternity.Pieces[nb].ligne = -1;
				tab_piece_rest[nb] = nb;
			}
			printf("col %i et lig %i\n", Eternity.Pieces[nb].colonne, Eternity.Pieces[nb].ligne);
			printf("tableau %i\n", tab_piece_rest[nb]);
			printf("(%i) lecture de %i%i%i%i\n",nb, Eternity.Pieces[nb].nord, Eternity.Pieces[nb].est, Eternity.Pieces[nb].sud, Eternity.Pieces[nb].ouest);
			nb++;
		}

	}
	else
	{
		printf("pas cool... \n");
	}
	
	solver(Eternity, ordre, 0, tab_piece_rest);
}
